package no.rodland.acc.db;

import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;

/**
 * Created by IntelliJ IDEA.
 *
 * @Since: Jun 18, 2010 12:09:40 PM
 * @Author: fmr
 */
public abstract class AbstractRow implements DbRow {

    private int id;
    private DateTime updated;
    private DateTime created;
    private DbRowComparator comparator = new DbRowComparator();

    /**
     * Convention: use 0 for new rows to insert.
     *
     * @param id      0 for new rows, otherwise the id of the row
     * @param updated the date the row was last updated
     * @param created the date the row was created
     */
    protected AbstractRow(int id, DateTime updated, DateTime created) {
        this.id = id;
        this.updated = updated;
        this.created = created;
    }

    public abstract boolean usesIdentity();

    public int getId() {
        return id;
    }

    public DateTime getCreatedDate() {
        return created;
    }

    public DateTime getUpdatedDate() {
        return updated;
    }

    @Override
    public DateTime getDate() {
        return getUpdatedDate();
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder();
        sb.append(", table-name: ").append(getTableName());
        sb.append(", id=").append(id);
        sb.append(", updated=").append(updated);
        sb.append(", created=").append(created);
        return sb.toString();
    }

    public boolean isNew() {
        return id == 0 && created == null;
    }

    @Override
    public boolean inDb() {
        return !isNew();
    }

    @Override
    public String getInsertSql() {
        if (inDb()) {
            throw new UnsupportedOperationException("Cannot insert a row already in db.");
        }
        return "INSERT INTO " +
                getTableName() + " (" +
                getFieldNamesAsString() + ", created_date) " +
                "VALUES(" + getQuestions() + ", now())";
    }

    @Override
    public String getDeleteSql() {
        if (isNew()) {
            throw new UnsupportedOperationException("Cannot delete a new row.");
        }
        return "delete from " + getTableName() + " where id = " + getId();
    }

    @Override
    public String getUpdateSql() {
        if (isNew()) {
            throw new UnsupportedOperationException("Cannot update a new row.");
        }
        StringBuffer sql = new StringBuffer("update ");
        sql.append(getTableName());
        sql.append(" set ");
        int i = 0;
        for (String col : getColumns()) {
            sql.append(col);
            sql.append("=?");
            i++;
            if (!((i + 1) == getColumns().length)) {
                sql.append(", ");
            }
        }
        sql.append(" where id=").append(getId());
        return sql.toString();
    }

    private String getFieldNamesAsString() {
        String[] fields = getColumns();
        if (fields == null || fields.length == 0) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        for (String field : fields) {
            sb.append(field).append(",");
        }
        return dropLastChar(sb.toString());
    }

    private String getQuestions() {
        String[] fields = getColumns();
        if (fields == null || fields.length == 0) {
            return "";
        }

        String questions = StringUtils.repeat("?,", fields.length);
        return dropLastChar(questions);
    }

    private static String dropLastChar(String str) {
        return str.substring(0, str.length() - 1);
    }

    public void setUpdated(DateTime updatedDate) {
        this.updated = updatedDate;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setCreated(DateTime created) {
        this.created = created;
    }

    @Override
    public int compareTo(DbRow o) {
        return comparator.compare(this, o);
    }

    @Override
    public abstract boolean equals(Object o);

    @Override
    public abstract int hashCode();
}
